package fr.ants.model;

import java.util.Stack;

import fr.ants.model.ai.behaviour.AntBehavior;
import fr.ants.model.ai.behaviour.AntState;

/** 
 * <p>Represents an ant. Each ant belong to a nest and has a specific behavior.</p>
 *
 * @author Vianney DUPOY DE GUITARD
 */
public class Ant {

	/** The behavior of the ant. */
	private AntBehavior behavior;

	/** This is the path followed by the ant. */
	private Stack<Node> path = new Stack<>();

	/** The nest of this ant. */
	private Nest nest;

	/** The node where this ant is. */
	private Node node;

	/** Lifespan of the ant. Once it reaches 0, the ant dies. */
	private int lifespan = 0;

	/** The quantity of food the ant can carry. */
	private int foodCapacity = 60;

	/** The quantity of food the ant has. */
	private float food = 0;

	/** The quantity of food collected per bite. */
	private int foodPerBite = 20;

	/**
	 * Progression of ant over the node. 0 means it hasn't started walking on it. 
	 * Values above 100 mean that the ant has managed to cross this node.
	 */
	private int moveProgress = 0;

	/**
	 * Creates a new ant somewhere on the grid.
	 * @param pNode : the node where the ant is.
	 * @param pNode : the nest this ant is from.
	 * @param pBehavior : the ant's behavior.
	 */
	public Ant(Node pNode, Nest pNest, AntBehavior pBehavior) {
		node = pNode;
		nest = pNest;
		lifespan = nest.getInitialAntLifespan();
		node.addAnt(this);
		behavior = pBehavior;
	}

	/** 
	 * Let the ant find what to do, find a goal, and move.
	 * A goal is a destination represented by coordinates to a point on the grid.
	 *
	 * @param grid : the world grid.
	 */
	public void next(Grid grid) {
		if (isAlive()) {
			behavior.live(this, grid);
			lifespan--;
		} else {
			kill();
		}
	}

	/** @return the node the ant is on. */
	public Node getNode() {
		return node;
	}

	/**
	 * Sets the node where the ant is.
	 * @param pNode : the node where the ant is.
	 */
	public void setNode(Node pNode) {
		node = pNode;
	}

	/** @return the path followed by the ant. */
	public Stack<Node> getPath() {
		return path;
	}

	/**
	 * Sets the path followed by the ant.
	 * @param path : the new path.
	 */
	public void setPath(Stack<Node> path) {
		this.path = path;
	}

	/** @return the quantity of food the ant can carry. */
	public int getFoodCapacity() {
		return foodCapacity;
	}

	/**
	 * Sets the quantity of food the ant can carry.
	 * @param foodCapacity : the new quantity.
	 */
	public void setFoodCapacity(int foodCapacity) {
		this.foodCapacity = foodCapacity;
	}

	/** @return the quantity of food the ant is carrying. */
	public float getFood() {
		return food;
	}

	/**
	 * Set the quantity of food the ant is carrying.
	 * @param food : the new quantity.
	 */
	public void setFood(float food) {
		this.food = food;
	}

	/**
	 * Adds food to the ant.
	 * @param food : the quantity to add.
	 */
	public void addFood(float food) {
		this.food += food;
	}

	/**
	 * Release the food carried by the ant (i.e. food = 0 after this call).
	 * @return the amount of food released.
	 */
	public float releaseFood() {
		float qty = food;
		food = 0;
		return qty;
	}

	/** @return the quantity of food obtained per bite. */
	public float getFoodPerBite() {
		return foodPerBite < (foodCapacity - food) ? foodPerBite : foodCapacity - food;
	}

	/**
	 * Set the quantity of food the ant is carrying.
	 * @param food : the new quantity.
	 */
	public void setFoodPerBite(int foodPerBite) {
		this.foodPerBite = foodPerBite;
	}

	/** @return the nest this ant is from. */
	public Nest getNest() {
		return nest;
	}

	/** @return true if the ant is alive. */
	public boolean isAlive() {
		return lifespan > 0;
	}

	/** Kills the ant. */
	public void kill() {
		lifespan = 0;
		node.getAnts().remove(this);
		nest.getAnts().remove(this);
	}

	/** Resets the ant. */
	public void reset() {
		node = nest.getNode();
	}

	/** @return the current state of the ant. */
	public AntState getState() {
		return behavior.getAntState();
	}

	/**
	 * @return the moveProgress
	 */
	public int getMoveProgress() {
		return moveProgress;
	}

	/**
	 * @param moveProgress the moveProgress to set
	 */
	public void setMoveProgress(int moveProgress) {
		this.moveProgress = moveProgress;
	}

	/**
	 * @return the lifespan
	 */
	protected int getLifespan() {
		return lifespan;
	}
}